//
//  InputBoxBaseManager.swift
//  Swift-Codedase
//
//  Created by xyanl on 2024/8/28.
//  Copyright © 2024 考拉🐨. All rights reserved.
//

import UIKit

class InputBoxBaseManager: NSObject {
    
    weak var viewController: UIViewController!
    // 输入栏TextView的高度发送变化的动画时长（秒），默认：0.2s
    var animationDuration: TimeInterval = 0.2
    
    init(viewController: UIViewController!) {
        self.viewController = viewController
        super.init()
        //  输入栏TextView的高度发送变化的动画时长（秒）
        animationDuration = 0.2
        
        NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillShowNotification(obj:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDidShowNotification(obj:)), name: UIResponder.keyboardDidShowNotification, object: nil)
        
        NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillHideNotification(obj:)), name: UIResponder.keyboardWillHideNotification, object: nil)
        
        NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDidHideNotification(obj:)), name: UIResponder.keyboardDidHideNotification, object: nil)
        
    }
    
    // 在模拟器上测试：如果模拟器的键盘无法弹出，那么点击输入栏不会收到 WillShowNotification，而是直接收到 WillHideNotification，但是这种情况下依然会走 textViewShouldBeginEditing
    @objc func onKeyboardWillShowNotification(obj: Notification) {
        
        if let userInfo: [AnyHashable: Any] = obj.userInfo {
            
            let screenBounds: CGRect
            if #available(iOS 13.0, *), let screen: UIScreen = obj.object as? UIScreen {
                screenBounds = screen.bounds
            } else {
                screenBounds = UIScreen.main.bounds
            }
            
            var keyboardRect: CGRect = .zero
            //  Getting UIKeyboardSize.
            if var kbFrame: CGRect = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
                
                // If this is floating keyboard
                if kbFrame.width < screenBounds.width,
                   kbFrame.maxY < screenBounds.height {
                    kbFrame.size = CGSize(width: kbFrame.size.width, height: 0)
                } else {
                    // (Bug ID: #469) (Bug ID: #381) (Bug ID: #1506)
                    // Calculating actual keyboard covered size respect to window,
                    // keyboard frame may be different when hardware keyboard is attached
                    let keyboardHeight = CGFloat.maximum(screenBounds.height - kbFrame.minY, 0)
                    kbFrame.size = CGSize(width: kbFrame.size.width, height: keyboardHeight)
                }
                keyboardRect = kbFrame
                
            } else {
                keyboardRect = CGRect(x: 0, y: screenBounds.height, width: screenBounds.width, height: 0)
            }
            
            
            var animationCurve: UIView.AnimationCurve
            //  Getting keyboard animation.
            if let curveValue: Int = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int,
               let curve: UIView.AnimationCurve = UIView.AnimationCurve(rawValue: curveValue) {
                animationCurve = curve
            } else {
                animationCurve = .easeOut
            }
            
            var animationDuration: TimeInterval
            //  Getting keyboard animation duration
            if let duration: TimeInterval = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval,
               duration != 0.0 {
                animationDuration = duration
            } else {
                animationDuration = 0.25
            }
            
            onKeyboardWillShowOrHideByNotifications(keyboardRect: keyboardRect, animationOptions: animationOptionsForCurve(curve: animationCurve), duration: animationDuration, showKeyboard: true)
        }
    }
    
    @objc func onKeyboardWillHideNotification(obj: Notification) {
        
        if let userInfo: [AnyHashable: Any] = obj.userInfo {
            
            let screenBounds: CGRect
            if #available(iOS 13.0, *), let screen: UIScreen = obj.object as? UIScreen {
                screenBounds = screen.bounds
            } else {
                screenBounds = UIScreen.main.bounds
            }
            
            var keyboardRect: CGRect = .zero
            //  Getting UIKeyboardSize.
            if var kbFrame: CGRect = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
                
                // If this is floating keyboard
                if kbFrame.width < screenBounds.width,
                   kbFrame.maxY < screenBounds.height {
                    kbFrame.size = CGSize(width: kbFrame.size.width, height: 0)
                } else {
                    // (Bug ID: #469) (Bug ID: #381) (Bug ID: #1506)
                    // Calculating actual keyboard covered size respect to window,
                    // keyboard frame may be different when hardware keyboard is attached
                    let keyboardHeight = CGFloat.maximum(screenBounds.height - kbFrame.minY, 0)
                    kbFrame.size = CGSize(width: kbFrame.size.width, height: keyboardHeight)
                }
                keyboardRect = kbFrame
                
            } else {
                keyboardRect = CGRect(x: 0, y: screenBounds.height, width: screenBounds.width, height: 0)
            }
            
            
            var animationCurve: UIView.AnimationCurve
            //  Getting keyboard animation.
            if let curveValue: Int = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int,
               let curve: UIView.AnimationCurve = UIView.AnimationCurve(rawValue: curveValue) {
                animationCurve = curve
            } else {
                animationCurve = .easeOut
            }
            
            var animationDuration: TimeInterval
            //  Getting keyboard animation duration
            if let duration: TimeInterval = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval,
               duration != 0.0 {
                animationDuration = duration
            } else {
                animationDuration = 0.25
            }
            
            onKeyboardWillShowOrHideByNotifications(keyboardRect: keyboardRect, animationOptions: animationOptionsForCurve(curve: animationCurve), duration: animationDuration, showKeyboard: false)
        }
    }
    
    @objc func onKeyboardDidShowNotification(obj: Notification) {
        
    }
    
    @objc func onKeyboardDidHideNotification(obj: Notification) {
        
    }
    
    // MARK: - Need Override
    @objc func onKeyboardWillShowOrHideByNotifications(keyboardRect: CGRect, animationOptions: UIView.AnimationOptions, duration: TimeInterval, showKeyboard: Bool) {}
    
    private func animationOptionsForCurve(curve: UIView.AnimationCurve) -> UIView.AnimationOptions {
        switch curve {
        case .easeInOut:
            return .curveEaseInOut
            
        case .easeIn:
            return .curveEaseIn
            
        case .easeOut:
            return .curveEaseOut
            
        case .linear:
            return .curveLinear
            
        default:
            return []
        }
    }
    
}

